/*
 * GameComponentManager.h
 *
 *  Created on: May 13, 2012
 *      Author: mklingen
 */

#ifndef GAMECOMPONENTMANAGER_H
#define GAMECOMPONENTMANAGER_H

#include "GameComponent.h"
#include "GameComponentDefs.h"
#include <QKeyEvent>
#include <QMouseEvent>

namespace kling
{
    class GameComponent;
    class GameWindow;
    // Class which keeps track of all the allocated game components,
    // updates them, draws them, and so on.
    class GameComponentManager
    {
        public:
            GameComponentManager(GameWindow* gameWindow = NULL);
            virtual ~GameComponentManager();

            void Initialize();

            inline GameWindow* GetGameWindow() { return m_gameWindow; }
            inline GameComponent* GetRootComponent() { return m_rootComponent; }

            inline std::map<kling::GlobalComponentID, GameComponent*>& GetComponents() { return m_components; }

            inline kling::GlobalComponentID GetNextGlobalID() { return ++m_maxGlobalID; }

            // Adds the given component to the map with the given ID. Returns false if the component
            // exists already, or if the ID is not unique.
            bool AddComponent(GameComponent* gameComponent, GlobalComponentID id = INVALID_GLOBAL_ID);


            inline bool HasComponentWithGlobalID(GlobalComponentID id) { return m_components.find(id) != m_components.end(); }

            // Updates every component and takes care of transforms
            void Update(double deltaTimeSeconds);

            // Draws every component.
            void Render(double deltaTimeSeconds);

            // Returns the component with the given id if it exists, or NULL otherwise.
            GameComponent* GetComponentWithGlobalID(GlobalComponentID id);

            // Returns a vector containing all components with the given type
            template <class ComponentType> std::vector<ComponentType*> GetAllComponentsByType()
            {
                std::vector<ComponentType*> toReturn;
                for(std::map<GlobalComponentID, GameComponent*>::iterator it = m_components.begin(); it != m_components.end(); it++)
                {
                    ComponentType* component = dynamic_cast<ComponentType*>(it->second);

                    if(component)
                    {
                        toReturn.push_back(component);
                    }
                }

                return toReturn;
            }

            bool IsInitialized();

            void InitializeAllComponents();

            virtual void HandleKeyEvent(QKeyEvent* keyEvent);
            virtual void HandleMouseEvent(QMouseEvent* mouseEvent);

        protected:
            GameWindow* m_gameWindow;
            GameComponent* m_rootComponent;
            kling::GlobalComponentID m_maxGlobalID;
            std::map<kling::GlobalComponentID, GameComponent*> m_components;
            bool m_isInitialized;

    };

} /* namespace kling */
#endif /* GAMECOMPONENTMANAGER_H_ */
